import java.util.Enumeration;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author GAX
 * @date 2025-09-06
 */
public class CustomizedCommunicationDemo {
    public static void main(String[] args) {
        // 创建共享资源类对象
        ShareResource resource = new ShareResource();

        // 创建线程
        new Thread(()->{
            try {
                for (int i = 0; i < 10; i ++) {
                    resource.print5();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"A").start();

        new Thread(()->{
            try {
                for (int i = 0; i < 10; i ++) {
                    resource.print10();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"B").start();

        new Thread(()->{
            try {
                for (int i = 0; i < 10; i ++) {
                    resource.print15();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"C").start();
    }
}

// 创建资源类
class ShareResource {
    // 线程的标识，假设 1 代表 A，2 代表 B，3 代表 C
    private int flag = 1;
    private final Lock lock = new ReentrantLock();

    // 为每个线程创建专用的 Condition
    private final Condition conditionA = lock.newCondition();
    private final Condition conditionB = lock.newCondition();
    private final Condition conditionC = lock.newCondition();

    public void print5() throws InterruptedException {
        lock.lock();
        try {
            // ① 判断：需要使用 while
            while (flag != 1) {
                // A 线程会在 condition A 上等待
                conditionA.await();
            }
            // ② 干活：打印 5 次
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " 打印了：" + (i+1) + " 次");
            }
            // ③ 通知：精确唤醒 B 线程
            // 调整 flag 为 B 线程对应的 flag，即 flag = 2
            flag = 2;
            conditionB.signal();
        } finally {
            lock.unlock();
        }
    }

    public void print10() throws InterruptedException {
        lock.lock();
        try {
            // ① 判断，需要使用 while
            while (flag != 2) {
                // 在线程 B 上等待
                conditionB.await();
            }
            // ② 干活，打印 10 次
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " 打印了：" + (i+1) + " 次");
            }
            // ③ 通知
            flag = 3;
            // 只唤醒 C 线程
            conditionC.signal();
        } finally {
            lock.unlock();
        }
    }

    public void print15() throws InterruptedException {
        lock.lock();
        // ① 判断
        while (flag != 3) {
            // 在线程 C 上等待
            conditionC.await();
        }
        // ② 干活
        for (int i = 0; i < 15; i++) {
            System.out.println(Thread.currentThread().getName() + " 打印了：" + (i+1) + " 次");
        }
        // ③ 通知
        flag = 1;
        // 只唤醒 A 线程
        conditionA.signal();
    }
}
